package com.bt.dmdb.enums;

import java.util.Collection;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

public enum Constraint {
    EQ("equals") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return ignoreCase ? Restrictions.eq(property, value).ignoreCase() : Restrictions.eq(property, value);
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            if ((StringUtils.isEmpty(value))) { return new StringBuilder("lower(").append(property).append(") is null").toString(); }
            return ignoreCase ? new StringBuilder("lower(").append(property).append(") = lower('").append(value).append("')").toString() : new StringBuilder(property).append("=")
                    .append(value).toString();
        }
    },
    GT("gt") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.gt(property, value);
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            value = NumberUtils.isNumber(value) ? value : "'" + value + "'";
            return (new StringBuilder(property)).append(">").append(value).toString();
        }
    },
    LT("lt") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.lt(property, value);
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            value = NumberUtils.isNumber(value) ? value : "'" + value + "'";
            return (new StringBuilder()).append(property).append("<").append(value).toString();
        }
    },
    CONTAINS("contains") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.like(property, value.toString(), MatchMode.ANYWHERE).ignoreCase();
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            return (new StringBuilder("lower(")).append(property).append(") like lower('%").append(value).append("%')").toString();
        }
    },
    NOT_CONTAINS("notcontains") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.not(Restrictions.like(property, value.toString(), MatchMode.ANYWHERE).ignoreCase());
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            return (new StringBuilder("lower(")).append(property).append(") not like lower('%").append(value).append("%')").toString();
        }
    },
    NOT_EQ("notequals") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return ignoreCase ? Restrictions.ne(property, value).ignoreCase() : Restrictions.ne(property, value);
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            if ((StringUtils.isEmpty(value))) { return new StringBuilder("lower(").append(property).append(") is not null").toString(); }
            return ignoreCase ? new StringBuilder("lower(").append(property).append(") != lower('").append(value).append("')").toString() : new StringBuilder(property).append("!=")
                    .append(value).toString();
        }
    },
    START_WITH("starts with") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.like(property, value.toString(), MatchMode.START).ignoreCase();
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            return (new StringBuilder("lower(")).append(property).append(") like lower('").append(value).append("%')").toString();
        }
    },
    END_WITH("ends with") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.like(property, value.toString(), MatchMode.END).ignoreCase();
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            return (new StringBuilder("lower(")).append(property).append(") like lower('%").append(value).append("')").toString();
        }
    },
    IN("in") {

        @SuppressWarnings("rawtypes")
        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.in(property, (Collection) value);
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            return "";
        }
    },
    DATE_CONTAINS("date contains") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.like(property, value);
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            return new StringBuilder(property).append(" like '%").append(value).append("%'").toString();
        }
    },
    CLOB_EQ("clobeq") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.like(property, value.toString(), MatchMode.ANYWHERE).ignoreCase();
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            return (new StringBuilder("lower(")).append(property).append("||',') like lower('%").append(value).append(",%')").toString();
        }
    },
    CLOB_CONTAINS("clobcontains") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.like(property, value.toString(), MatchMode.ANYWHERE).ignoreCase();
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            return (new StringBuilder("lower(")).append(property).append(") like lower('%").append(value).append("%')").toString();
        }
    },
    CLOB_START("clobstart") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.like(property, value.toString(), MatchMode.ANYWHERE).ignoreCase();
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            return (new StringBuilder("lower(','||")).append(property).append(") like lower('%,").append(value).append("%')").toString();
        }
    },
    CLOB_END("clobend") {

        public Criterion getCriterion(String property, Object value, boolean ignoreCase) {
            return Restrictions.like(property, value.toString(), MatchMode.ANYWHERE).ignoreCase();
        }

        @Override
        public String getFilter(String property, String value, boolean ignoreCase) {
            return (new StringBuilder("lower(")).append(property).append("||',') like lower('%").append(value).append(",%')").toString();
        }
    };

    public String value;

    public abstract Criterion getCriterion(String property, Object value, boolean ignoreCase);

    public abstract String getFilter(String property, String value, boolean ignoreCase);

    private Constraint(String value) {
        this.value = value;
    }

    public static Constraint getConstraint(String value) {
        for (Constraint searchType : Constraint.values()) {
            if (searchType.value.equals(value)) { return searchType; }
        }
        return EQ;
    }
}
